home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / dos / fs / backup20.10 < prev    next >
Internet Message Format  |  1988-10-25  |  51KB

  1. Path: xanth!nic.MR.NET!tank!mimsy!dftsrv!ames!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i025:  backup - file backup utility V2.00
  5. Message-ID: <9845@swan.ulowell.edu>
  6. Date: 25 Oct 88 04:49:32 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 2193
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: dillon@cory.berkeley.edu (Matt Dillon)
  12. Posting-number: Volume 2, Issue 25
  13. Archive-name: dos/fs/backup200.1
  14.  
  15. # This is a shell archive.  Remove anything before this line
  16. # then unpack it by saving it in a file and typing "sh file"
  17. # (Files unpacked will be owned by you and have default permissions).
  18. # This archive contains the following files:
  19. #    backup.doc
  20. #    Makefile
  21. #    backup.c
  22. #
  23. if `test ! -s backup.doc`
  24. then
  25. echo "writing backup.doc"
  26. cat > backup.doc << '\Rogue\Monster\'
  27.  
  28.                    BACKUP.DOC
  29.  
  30.                  V2.00
  31.  
  32.                 16 October 1988
  33.      (c)Copyright 1988, Matthew Dillon, All Rights Reserved
  34.            Freely Distributable for non-profit only
  35.  
  36.  
  37.                   (I)
  38.                 OVERVIEW
  39.  
  40.     Backup and Restore (same executable, just renamed) allow you to backup
  41.     any directory tree with optional compression, and later extract all
  42.     or part of the tree.  The protection, date, and file comment is saved
  43.     with each file.
  44.  
  45.     SEE SECTION (6), FLOPICAL BACKUP, for options pertaining to backing
  46.     up directly to floppies.
  47.  
  48.     LIMITATIONS:    When using -c (compress), the entire result of the
  49.     compressed file must fit into memory.  Any files (after compression,
  50.     if any) larger than a floppy when backing up to floppies cannot be
  51.     handled yet.
  52.  
  53.  
  54.                   (I)
  55.                   INSTALLATION
  56.  
  57.     Copy the (1) executable to your C: directory twice, naming one
  58.     'Backup' and the other 'Restore'.  The program looks at the first
  59.     character of its name to determine whether the default is to backup
  60.     or restore.  If you don't have the space, all is not lost ... you
  61.     simply need to specify backup or restore explicitly with the options
  62.     (-b or -r).
  63.  
  64.                    (2)
  65.                  EXOTIC FEATURES
  66.  
  67.     Backup does not write directory trees which contain no files.  Thus,
  68.     when doing incremental backups on a large hard disk, the structure of
  69.     directory sub-trees which have no new files in them will not be
  70.     written.  So if you only modified a couple of files since the last
  71.     backup, there won't be 50K of structure-overhead.
  72.  
  73.     You can specify compression (-c) in the backup.  All files are
  74.     compressed (there must be enough RAM to hold the largest file in
  75.     its compressed state).  Those files which would turn out larger after
  76.     compression than before are NOT compressed.  Certain file suffixes
  77.     cause the compression attempt to be skipped entire:  .Z, .ARC, and .ZOO
  78.     files
  79.  
  80.       IT IS SUGGESTED YOU USE THE COMPRESSION FEATURE EVEN THOUGH IT
  81.       SLOWS DOWN THE BACKUP.  The resulting backup file will be
  82.       significantly reduced in size.  Even though a full backup will
  83.       take a long time, you only do that every once in a while and
  84.       as incremental backups are shorter, they take much less time.
  85.  
  86.     'Pick' patterns are supported (backup only paths which match the
  87.     specified patterns), and 'Discard' patterns are supported (do not backup
  88.     paths which match the specified patterns).    Discard patterns override
  89.     Pick patterns.
  90.  
  91.                   (3)
  92.                 OPTIONS
  93.  
  94.     Here is a list of Backup/Restore options.
  95.  
  96.     -A    ARCHIVE. (Backup) Causes the archive bit to be cleared
  97.         on files being backed up.  (Protection bit -> 1)
  98.  
  99.         (Restore):  If specified, the archive bit is cleared on
  100.         restored files.  Otherwise the archive bit will be set,
  101.         causing the files to be backed up again on the next
  102.         incremental backup.
  103.  
  104.     -U    UPDATE.  (Backup) Restricts the backup to only those files
  105.         which have the archive bit set.  (Protection bit == 0)
  106.  
  107.     -b    BACKUP    (this is the default if the first character in
  108.         the executable is a 'b')
  109.  
  110.     -r    RESTORE (this is the default if the first character in
  111.         the executable is an 'r')
  112.  
  113.     -a    APPEND (Backup)     Cause the backup to be appended to
  114.         the specified (-o) file rather than overwriting it.  Useful
  115.         for incremental backups.
  116.  
  117.     -c    COMPRESS (Backup)   Cause all files to be compressed, if
  118.         possible.  Restore automatically decompresses files which
  119.         have been compressed.  This is the same algorithm used
  120.         in the UNIX compress command.
  121.  
  122.         NO COMPRESSION WILL EVEN BE ATTEMPED ON FILES WITH THE
  123.         FOLLOWING SUFFIXES: .Z .ARC .ZOO
  124.  
  125.     -f[#kb] Turn on backup fragmentation and specify the fragment size,
  126.         default 800K (for backing up to floppies).  NOTE: Currently,
  127.         files larger than the fragment size cannot be backed up!
  128.  
  129.         Note: a suffix is added to the file name w/ a sequence
  130.         number, but each fragment is a complete backup file unto
  131.         itself and may be restored out of order.
  132.  
  133.         Any numerical value specified is in K, i.e. -f800 == 800K
  134.  
  135.     -Fvol:    Add the volume (df0:, df1:, etc..) to the drive sequencing
  136.         list.  The idea is to specify several -F options which are
  137.         cycled through and prefix each fragment.  This also
  138.         enables prompting... the program prompts whenever it
  139.         switches to the next fragment.
  140.  
  141.         If -F is not specified at all and -f is, no prompting
  142.         occurs.
  143.  
  144.     -s    Only display directories as we go along
  145.  
  146.     -S    Silent... don't display files or directories
  147.  
  148.     -v    Verbose... display those files which will NOT be backed
  149.         up as well as those that will.
  150.  
  151.     -l/-t    (both do the same thing).  (Restore)   LIST the archive
  152.         only, do not do an actual restore.
  153.  
  154.     -T    (Restore)   Restore ONLY the timestamp, comment, and
  155.         protection fields.  This is incredibly useful to
  156.         restore timestamp information to files that already
  157.         exist.    NO files are overwritten or created on the
  158.         destination volume(s).
  159.  
  160.     -n#    (Backup)    Sets the output buffer size, in KILOBYTES.
  161.         Default is 64.
  162.  
  163.     -pPAT    (Backup)    Restrict the backup to files which match the
  164.         specified pattern.  Up to 32 patterns may be specified.
  165.  
  166.         (Restore)   Extract only those files which match the
  167.         specified pattern.
  168.  
  169.         NOTE:  The pattern is matched with the COMPLETE PATH as
  170.         shown in the -t option.  '*' and '?' wildcarding is supported
  171.  
  172.     -dPAT    (Backup)    Do not backup files which match the specified
  173.         pattern.   Up to 32 patterns may be specified.
  174.  
  175.         (Restore)   Do not extract files which match the specified
  176.         pattern.
  177.  
  178.         NOTE: The pattern is matched with the COMPLETE PATH as
  179.         shown in the -t option.  '*' and '?' wildcarding is supported.
  180.  
  181.     -oFILE    (Backup)    Specify the OUTPUT FILE for a backup.  IF NO
  182.         OUTPUT FILE IS SPECIFIED, NO OUTPUT FILE IS CREATED.  I.E.
  183.         you can take a second pass just to clear the archive bit.
  184.  
  185.         (Restore)   Specify the directory to place the restored
  186.         directory tree.  (This overrides the volume the backup
  187.         was saved from).  If no directory specified, the original
  188.         volume used in the backup will be restored to.    If no
  189.         volume was specified in the backup but rather a relative
  190.         path was, the restore will be relative to the current
  191.         directory.
  192.  
  193.                   (4)
  194.               STANDARD METHOD OF BACKING UP
  195.  
  196.     Note that with combinations of -o, -A, and -U, you have many choices
  197.     available to you when backing up files.  For hard disks, backups are
  198.     normally done in two phases:
  199.  
  200.     -Once a month do a complete backup of your hard disk
  201.     -Every day do a much smaller 'incremental' backup which backs
  202.      up only those files which have been modified/created since the
  203.      last backup.
  204.  
  205.     The master backup, plus the N incremental backups together
  206.     reconstruct your disk up to the moment.  After a while the
  207.     number of incremental backups will be so great (and messy),
  208.     that you will want to do another complete backup and start
  209.     again.
  210.  
  211.     IN THIS WAY, the COMPRESS option can be put to good use.  The
  212.     incremental backups are usually small, and can be compressed
  213.     relatively quickly.  The complete backup should also be compressed
  214.     (-c in case you forgot) though this will take a much longer time...
  215.     but then again the complete backup is not done every day.
  216.  
  217.     UPDATING THE ARCHIVE BIT ON THE FLY VERSES TAKING A SECOND PASS.
  218.     Updating the archive bit involves writing to the disk.  For complete
  219.     safety you probably do NOT want to update the archive bit while you
  220.     are backing up the files in question.  The following two-pass method
  221.     works well:
  222.  
  223.         (COMPLETE BACKUP)
  224.  
  225.     backup    -c -d"*.o" volume: -ooutput
  226.     backup    -A volume:
  227.  
  228.         (INCREMENTAL BACKUP)
  229.  
  230.     backup -U -c -d"*.o" volume: -ooutput
  231.     backup -A volume:
  232.  
  233.     The -d option is saying "Don't backup all those object modules I left
  234.     laying around".
  235.  
  236.     The first command backs up only those files which have be modified
  237.     or created but does NOT update the archive bit.  The second command
  238.     updates the archive bit without doing anything else (no output file
  239.     is specified and thus none is created).  The second command goes
  240.     extremely quickly since files are not actually read.
  241.  
  242.     For your INCREMENTAL backups, risking modifying the archive bit while
  243.     backing the files up is feasible,  Since very few files will be
  244.     backed up (comparitively):
  245.  
  246.     backup -a -UA -c -d"*.o" volume: -ooutput
  247.  
  248.     In this case I use the -a option (append).  You might NOT want to do
  249.     this and save the incremental backups as separate files.
  250.  
  251.  
  252.                   (5)
  253.               STANDARD METHOD OF RESTORING
  254.  
  255.     Restoring a backup to the original volume: (Restore or Backup -r)
  256.  
  257.     NOTE:  If the -A option is specified, restored files will have
  258.     their Archive bit cleared.    If -A is NOT specified, files will have
  259.     their archive bit set and will thus be re-backed up on the next
  260.     incremental backup.
  261.  
  262.     NOTE:  When restoring files, remember that the incremental backups
  263.     will have the newest modifications and should be specified LAST:
  264.  
  265.     Restore completebkfile incr1 incr2 incr3....
  266.  
  267.     Partial Restore using -p:
  268.  
  269.     Restore -pstuffIWant bkfile1 bkfile2 bkfile3...
  270.  
  271.     ARCHIVE LISTING:
  272.  
  273.     Restore -t bkfile1 bkfile2....
  274.  
  275.     NOTE:    Two 'sizes' are given in the listing.  The first
  276.     is the # bytes the file takes up in the archive, the
  277.     second is the actual size of the file.
  278.  
  279.  
  280.                   (6)
  281.               FLOPICAL BACKUP AND RESTORE
  282.  
  283.     There are two problems associated with floppy backup and restore:
  284.  
  285.     (1) A single file on the HD may be two big for a single floppy
  286.     (2) It may take a lot of floppies to backup an HD
  287.  
  288.     Additionaly, one wants the following conveniences:
  289.  
  290.     (1) Be able to backup to a logical progression of (floppy) drives,
  291.     inserted blank disks in while the system is working on other
  292.     drives.
  293.  
  294.     (2) Be able to restore the same way
  295.  
  296.     (3) If one or more floppies is destroyed be able to restore from the
  297.     remaining floppies.
  298.  
  299.         Currently, you can specify which devices to cycle through
  300.         with the -F option (-Fdf0: -Fdf1: -Fdf2:), but BACKUP will
  301.         always prompt you before continuing.  Since it uses the
  302.         console device, you can specify the yes response as many
  303.         times as you have floppies in ready drives.
  304.  
  305.         Currently, files larger than the specified -f size (800K
  306.         default) cannot be handled if using -f/-F ... However, by
  307.         enabling compression larger files can still fit.
  308.  
  309.         Currently, the entire compressed result of a file must be
  310.         able to fit into memory during the backup.
  311.  
  312.  
  313.                    ***
  314.  
  315.     BACKUP.    Specify the -f option and then -Fvol: for each floppy
  316.     drive (in the order you want) to backup to.  Example:
  317.  
  318.     -f -Fdf0: -Fdf1:
  319.  
  320.     (Also keep in mind all the options listed in sections (3), (4), & (5))
  321.     Currently, you must have PRE-FORMATTED all your backup disks since the
  322.     backup/restore works through normal files.    The system will prompt for
  323.     readyness every time it completes a section.
  324.  
  325.     The backup process never deletes files, only creates or overwrites
  326.     them.  Thus, accidently sticking in a non-blank or incorrect backup
  327.     disk will probably result in a disk-full requester.... not Fatal, though
  328.     inconvenient.
  329.  
  330.     You must still specify the -o option to name the output file, which will
  331.     be prefixed with the next -F volume in sequence and suffixed with the
  332.     sequence number. (.nn)  The disk labels for your floppies may all be
  333.     the same.
  334.  
  335.     EXAMPLE:
  336.  
  337.     backup    -c -d"*.o" -f -Fdf0: -Fdf1: -Fdf2: volume: -oxxbak
  338.     backup    -A volume:
  339.  
  340.     NOTE:    You do NOT specifiy a volume prefix in the -o option ..
  341.     those specified by -F are automatically cycled through as the
  342.     prefix.
  343.  
  344.     * If your hard disk has enough space on it I suggest you backup to an
  345.       alternate partition using only -f (not -F which forces user prompts),
  346.       then copy the chunks to floppies after the entire backup has
  347.       completed.
  348.  
  349.                    ***
  350.  
  351.     RESTORE.    Restore works the same way.  EACH DISK IS INDEPENDANT!    You
  352.     may insert disks in any order to be restored.  Simply execute the
  353.     standard restore command in section (5) for each floppy.
  354.  
  355.     Destroyed disks may be skipped.  Currently, no support for partially
  356.     restored disks exists... i.e. the archive has be clean.
  357.  
  358.  
  359.  
  360. \Rogue\Monster\
  361. else
  362.   echo "will not over write backup.doc"
  363. fi
  364. if [ `wc -c backup.doc | awk '{printf $1}'` -ne 12107 ]
  365. then
  366. echo `wc -c backup.doc | awk '{print "Got " $1 ", Expected " 12107}'`
  367. fi
  368. if `test ! -s Makefile`
  369. then
  370. echo "writing Makefile"
  371. cat > Makefile << '\Rogue\Monster\'
  372.  
  373. #   Makefile for backup
  374.  
  375. SYMS=    include:symbols.m
  376. SYMC=    include:local/makesymbols.c
  377. CFLAGS= +L +I$(SYMS)
  378. LFLAGS= +Q
  379. DD=    srcc:
  380. OD=    T:
  381.  
  382. $(DD)backup:    backup.c
  383.     cc $(CFLAGS) backup.c -o $(OD)backup.o
  384.     ln +Q $(OD)backup.o -lsup32 -lc32 -o $(DD)backup
  385.     delete $(OD)backup.o
  386.  
  387. $(SYMS):    $(SYMC)
  388.     make -f include:local/Makefile
  389.  
  390. \Rogue\Monster\
  391. else
  392.   echo "will not over write Makefile"
  393. fi
  394. if [ `wc -c Makefile | awk '{printf $1}'` -ne 337 ]
  395. then
  396. echo `wc -c Makefile | awk '{print "Got " $1 ", Expected " 337}'`
  397. fi
  398. if `test ! -s backup.c`
  399. then
  400. echo "writing backup.c"
  401. cat > backup.c << '\Rogue\Monster\'
  402.  
  403. /*
  404.  * BACKUP.C
  405.  *
  406.  *  (C)Copyright 1986-88, Matthew Dillon, All Rights Reserved.
  407.  *  Permission is granted to distribute for non-profit only.
  408.  *
  409.  * This program will backup a filesystem or directory, creating a single
  410.  * output file which can later be RESTORE'd from.  It is a quick way to
  411.  * backup your work to a 'backup' disk.
  412.  *
  413.  *  backup [options] path path path ... path [-ooutputfile]
  414.  *
  415.  *    NOTE:    if -o is not specified, not output file will be created
  416.  *
  417.  *  options:
  418.  *
  419.  *    -A       ARCHIVE.  Clear the archive bit on backed up files
  420.  *
  421.  *    -U       UPDATE.     Backup only those files which have the archive bit
  422.  *           cleared.
  423.  *
  424.  *    -f[#KB]  Floppy... actually, this option is used to force the backup
  425.  *           program to automatically split up the backup files in #KB
  426.  *           sections (default 800).  I.E.  -f with nothing else will
  427.  *           use 800KB chunks.  -f200 would use 200KB chunks, etc...
  428.  *
  429.  *           PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
  430.  *           AND RESTORE
  431.  *
  432.  *    -Fvol    example: -FDF0: -FDF1:  This command specifies the ordering
  433.  *           and number of (floppy) drives to backup to.  This allows
  434.  *           one to change floppies in one drive while it is backing up
  435.  *           to another.  It automatically cycles through the drives but
  436.  *           you still must specify an initial output file (-ofile) to
  437.  *           determine the base name for the files.
  438.  *
  439.  *           This command also forces user prompting.
  440.  *
  441.  *           PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
  442.  *           AND RESTORE
  443.  *
  444.  *    -b       backup    (default if executable name is 'backup')
  445.  *
  446.  *    -r       restore    (default if executable nam is 'restore')
  447.  *
  448.  *    -a       append to the destination file.
  449.  *
  450.  *    -c       Compress files during backup
  451.  *
  452.  *    -s       Only display directories as we go along.
  453.  *
  454.  *    -l/-t    (either option) Causes a RESTORE to only LIST the files,
  455.  *           not do an actual restore.
  456.  *
  457.  *    -T       (Restore) TIMESTAMP, COMMENT, AND PROTECTION BITS ONLY.
  458.  *           NO files are created.  It is assumed the files already
  459.  *           exist.  The timestamp and other fields are transfered
  460.  *           from the backup file to the already-restored files (useful
  461.  *           if the files were restored with a copy command that did
  462.  *           non copy the timestamps.  Even if the backup file is old,
  463.  *           you can recover most of your time data).
  464.  *
  465.  *    -S       Silent.    Don't display files or directories.
  466.  *
  467.  *    -nKB     Set buffer size to use, in KB.
  468.  *
  469.  *    -v       Verbose... Additionaly, display those files which will NOT
  470.  *           be backed up.
  471.  *
  472.  *    -pPAT    only file-paths matching this pattern are backed up.  You
  473.  *           may specify more than one '-p' option.
  474.  *
  475.  *    -dPAT    file-paths matching this pattern are NOT backed up.  you
  476.  *           may specify more than one '-d' option.
  477.  *
  478.  *    -ofile   Output File
  479.  *
  480.  * ---------------------------------------------------------------------
  481.  *
  482.  * destination file format:
  483.  *
  484.  *  HDR = <HDR><N.B><datestamp>             -Backup Date
  485.  *  VOL = <VOL><name_size.B><name>            -VOLUME base
  486.  *  DDS = <DDS><name_size.B><name>            -down-directory
  487.  *  END = <END><0.B>                    -up directory
  488.  *  DAT = <DAT><N.B><datestamp>             -datestamp for file
  489.  *  PRO = <PRO><4.B><protection>            -protection for file
  490.  *  COM = <COM><N.B><comment>                -comment for file
  491.  *  FIL0= <FIL0><N.B><name><size.L><data>        -uncompressed file
  492.  *  FIL1= <FIL1><N.B><name><size.L><usize.L><data>  -compressed form #1
  493.  *  INC = <INC><12.B><ttlsize><strt><segsize>        -next file is part of an
  494.  *                             incomplete file
  495.  */
  496.  
  497. #include <stdio.h>
  498. #include <fcntl.h>
  499. #include <local/typedefs.h>
  500.  
  501. #define SDIR    struct _SDIR
  502. #define SCOMP    struct _SCOMP
  503.  
  504. SCOMP {
  505.     MNODE   Node;
  506.     uword   Bytes;    /*  allocated bytes            */
  507.     uword   N;
  508. };
  509.  
  510. SDIR {
  511.     MNODE   Node;    /*  node in dir tree            */
  512.     ubyte   Type;    /*  XDDS or XVOL            */
  513.     ubyte   HaveFile;    /*  Something was backed up in here */
  514.     char    *Element;    /*  path element            */
  515. };
  516.  
  517. #define XVOL    0x01
  518. #define XDDS    0x02
  519. #define XEND    0x03
  520. #define XDAT    0x04
  521. #define XPRO    0x05
  522. #define XCOM    0x06
  523. #define XFIL0    0x87
  524. #define XFIL1    0x88
  525. #define XHDR    0x09
  526. #define XINC    0x0A
  527.  
  528. ubyte    Break;
  529. ubyte    Restore;
  530. ubyte    ListOnly;
  531. ubyte    ShowFiles = 1;
  532. ubyte    ShowDirs  = 1;
  533. ubyte    Verbose;
  534. ubyte    Archive;
  535. ubyte    Update;
  536. ubyte    Append;
  537. ubyte    Compress;
  538. ubyte    TimeStampOnly;
  539. char    *OutFile;
  540. long    BacBytes;
  541. short    BacCnt = 1;
  542.  
  543. uword    NumPicks;
  544. uword    NumDels;
  545. char    *Picks[32];
  546. char    *Dels[32];
  547.  
  548. char DirPath[256];
  549. short DPLen;
  550.  
  551. long    BufSize = 65536;
  552. long    BufI;
  553. ubyte    *Buf;
  554. long    InBufSize = 8192;
  555. long    InBufI, InBufN;
  556. ubyte    *InBuf;
  557.  
  558. MLIST    VList;        /*    Volume list (-F), of NODEs              */
  559. MLIST    DList;        /*    Directory Stack             */
  560. long    CLen;        /*    Actual compressed file output length    */
  561. MLIST    CList;        /*    List of memory buffers            */
  562. SCOMP    *CWrite;    /*    Current memory buffer pointer        */
  563.  
  564. extern int Enable_Abort;
  565. extern void seekinputend();
  566. extern FIB *GetFileInfo();
  567. extern SCOMP *NewSComp();
  568. extern void *malloc(), *GetHead(), *GetTail(), *GetSucc(), *GetPred();
  569.  
  570. main(ac, av)
  571. char *av[];
  572. {
  573.     register short i, notdone;
  574.     register char  *str;
  575.  
  576.     NewList(&VList);
  577.     NewList(&DList);
  578.     NewList(&CList);
  579.  
  580.     Enable_Abort = 0;
  581.  
  582.  
  583.     for (str = av[0] + strlen(av[0]); str >= av[0] && *str != '/' && *str != ':'; --str);
  584.     ++str;
  585.     if ((*str|0x20) == 'r')
  586.     Restore = 1;
  587.  
  588.     if (ac == 1) {
  589.     printf("Backup/Restore V2.00, (c)Copyright 1988 Matthew Dillon, All Rights Reserved\n", str);
  590.     printf("%s -rbactlvASTU -d<pat> -p<pat> -f[#kb] -F<vol> -n<#kb> -ofile\n", str);
  591.     }
  592.  
  593.     for (i = 1; i < ac; ++i) {
  594.     str = av[i];
  595.     if (*str != '-')
  596.         continue;
  597.     notdone = 1;
  598.     ++str;
  599.     while (notdone && *str) {
  600.         switch(*str) {
  601.         case 'r':
  602.         Restore = 1;
  603.         break;
  604.         case 'b':
  605.         Restore = 0;
  606.         break;
  607.         case 'a':
  608.         Append = 1;
  609.         break;
  610.         case 'c':
  611.         Compress = 1;
  612.         break;
  613.         case 'd':
  614.         Dels[NumDels++] = str + 1;
  615.         notdone = 0;
  616.         break;
  617.         case 'f':
  618.         BacBytes = 800 * 1024;
  619.         if (str[1] >= '0' && str[1] <= '9') {
  620.             BacBytes = atoi(str+1) * 1024;
  621.             notdone = 0;
  622.         }
  623.         break;
  624.         case 'F':
  625.         {                    /*    strlen(str+1)+1 */
  626.             register NODE *node = malloc(sizeof(NODE)+strlen(str));
  627.             node->ln_Name = (char *)(node+1);
  628.             strcpy(node+1, str+1);
  629.             AddTail(&VList, node);
  630.         }
  631.         notdone = 0;
  632.         break;
  633.         case 'n':
  634.         BufSize = atoi(str+1) * 1024;
  635.         if (BufSize <= 0)
  636.             BufSize = 65536;
  637.         notdone = 0;
  638.         break;
  639.         case 'o':
  640.         OutFile = str + 1;
  641.         notdone = 0;
  642.         break;
  643.         case 'p':
  644.         Picks[NumPicks++] = str + 1;
  645.         notdone = 0;
  646.         break;
  647.         case 's':
  648.         ShowFiles = 0;
  649.         break;
  650.         case 't':
  651.         case 'l':
  652.         ListOnly = 1;
  653.         break;
  654.         case 'v':
  655.         Verbose= 1;
  656.         break;
  657.         case 'A':
  658.         Archive= 1;
  659.         break;
  660.         case 'S':
  661.         ShowFiles = 0;
  662.         ShowDirs  = 0;
  663.         break;
  664.         case 'T':
  665.         TimeStampOnly = 1;
  666.         break;
  667.         case 'U':
  668.         Update = 1;
  669.         break;
  670.         default:
  671.         puts("failure");
  672.         exit(20);
  673.         }
  674.         ++str;
  675.     }
  676.     }
  677.     Buf = malloc(BufSize);
  678.     if (Buf == NULL) {
  679.     printf("Unable to malloc %ld bytes\n", BufSize);
  680.     exit(20);
  681.     }
  682.     if (ListOnly)
  683.     InBufSize = 512;    /*  small buffer to avoid read overhead */
  684.                 /*  since we are skipping the meat    */
  685.  
  686.     InBuf = malloc(InBufSize);
  687.     if (InBuf == NULL) {
  688.     printf("Unable to malloc %ld bytes\n", InBufSize);
  689.     exit(20);
  690.     }
  691.  
  692.     if (Restore)
  693.     RestoreFiles(ac,av);
  694.     else
  695.     BackupFiles(ac,av);
  696. }
  697.  
  698. long SaveLock;
  699.  
  700. BackupFiles(ac, av)
  701. char *av[];
  702. {
  703.     register short i;
  704.     register char *str, *ptr;
  705.     char notdone;
  706.  
  707.     if (OutFile && openoutput(OutFile, Append, ((BacBytes)?1:0)) == 0)
  708.     exit(20);
  709.     if (OutFile) {      /*  write header    */
  710.     DATESTAMP Date;
  711.     DateStamp(&Date);
  712.     outentry(XHDR, sizeof(DATESTAMP), &Date);
  713.     }
  714.  
  715.     SaveLock = CurrentDir(DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
  716.  
  717.     for (i = 1; i < ac; ++i) {
  718.     str = av[i];
  719.     if (*str == '-')
  720.         continue;
  721.     /*
  722.      *  Push DDS entries for each name segment of the path
  723.      */
  724.  
  725.     notdone = 1;
  726.     while (notdone) {
  727.         for (ptr = str; *ptr && *ptr != ':' && *ptr != '/'; ++ptr);
  728.         switch(*ptr) {
  729.         case '/':   /*  normal directory    */
  730.         *ptr = 0;
  731.         PushDir(str, XDDS);
  732.         str = ptr + 1;
  733.         *ptr = '/';
  734.         break;
  735.         case ':':   /*  volume              */
  736.         *ptr = 0;
  737.         PushDir(str, XVOL);
  738.         str = ptr + 1;
  739.         *ptr = ':';
  740.         break;
  741.         default:    /*  directory or file    */
  742.         {
  743.             char *path = av[i];
  744.             FIB *fib;
  745.             long lock;
  746.  
  747.             if (fib = GetFileInfo(path, &lock)) {
  748.             if (fib->fib_DirEntryType > 0) {
  749.                 if (str[0])
  750.                 PushDir(str, XDDS);
  751.                 lock = scan_directory(fib, lock);
  752.                 if (str[0])
  753.                 PopDirs(1);
  754.             } else {
  755.                 lock = scan_file(fib, lock);
  756.             }
  757.             FreeFileInfo(fib, lock);
  758.             } else {
  759.             printf("Unable to get info for %s\n", av[i]);
  760.             }
  761.         }
  762.         notdone = 0;
  763.         break;
  764.         }
  765.     }
  766.     PopDirs(-1);
  767.     }
  768.  
  769.     UnLock(CurrentDir(SaveLock));
  770.     if (OutFile)
  771.     closeoutput();
  772. }
  773.  
  774. DATESTAMP Date;
  775. char Comment[256];
  776. char Scr[256];
  777. long Protection;
  778. long IncSize;        /*  Size of entire file     */
  779. long IncSeek;        /*  Seek offset into file   */
  780. long IncLen;        /*  # bytes in this segment */
  781.  
  782. RestoreFiles(ac, av)
  783. char *av[];
  784. {
  785.     register short i;
  786.     register char *str;
  787.     char notdone;
  788.     char havedate;
  789.     char havepro;
  790.     char havecom;
  791.     char haveinc;
  792.     long bytes;
  793.     long actual;
  794.     long lock;
  795.  
  796.     SaveLock = CurrentDir(lock = DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
  797.  
  798.     for (i = 1; i < ac; ++i) {
  799.     str = av[i];
  800.     if (*str == '-')
  801.         continue;
  802.     if (openinput(str) == 0) {
  803.         printf("Unable to open %s for input\n", str);
  804.         continue;
  805.     }
  806.     notdone = 1;
  807.     havedate = havepro = havecom = haveinc = 0;
  808.     while (notdone) {
  809.         short c = oreadchar();
  810.         short l = oreadchar();
  811.         switch(c) {
  812.         case -1:
  813.         notdone = 0;
  814.         break;
  815.         case XVOL:
  816.         oread(Scr, l);
  817.         Scr[l] = 0;
  818.         if (OutFile) {      /*  Restore to OutFile instead  */
  819.             register short j = strlen(OutFile);
  820.             strcpy(Scr, OutFile);
  821.             if (j && OutFile[j-1] == '/') {
  822.             c = XDDS;
  823.             Scr[j-1] = 0;
  824.             } else if (j && OutFile[j-1] == ':') {
  825.             c = XVOL;
  826.             Scr[j-1] = 0;
  827.             } else
  828.             c = XDDS;
  829.         }
  830.         PushDir(Scr, c);
  831.         if (ListOnly)
  832.             break;
  833.         lock = Lock(DirPath, SHARED_LOCK);  /*  DirPath incs ':'    */
  834.         if (lock == NULL && c == XDDS) {
  835.             if (lock = CreateDir(Scr))      /*  Scr excludes '/'    */
  836.             UnLock(lock);
  837.             lock = Lock(Scr, SHARED_LOCK);
  838.         }
  839.         {
  840.             SDIR *sd = GetTail(&DList);
  841.             sd->HaveFile = 1;            /*    don't remove dir    */
  842.         }
  843.         if (lock == NULL) {
  844.             printf("Unable to create directory %s\n", Scr);
  845.             notdone = 0;
  846.         } else {
  847.             UnLock(CurrentDir(lock));
  848.         }
  849.         break;
  850.         case XDDS:
  851.         oread(Scr, l);
  852.         Scr[l] = 0;
  853.         PushDir(Scr, XDDS);
  854.         if (ListOnly)
  855.             break;
  856.         lock = Lock(Scr, SHARED_LOCK);
  857.         if (lock == NULL) {
  858.             if (lock = CreateDir(Scr))
  859.             UnLock(lock);
  860.             lock = Lock(Scr, SHARED_LOCK);
  861.         } else {
  862.             SDIR *sd = GetTail(&DList);
  863.             sd->HaveFile = 1;            /*    don't remove dir    */
  864.         }
  865.         if (lock == NULL) {
  866.             printf("Unable to create directory %s\n", Scr);
  867.             notdone = 0;
  868.         } else {
  869.             UnLock(CurrentDir(lock));
  870.         }
  871.         break;
  872.         case XEND:
  873.         {
  874.             SDIR *sd = GetTail(&DList);
  875.             c = 1;
  876.             if (!sd)
  877.             break;
  878.             strcpy(Scr, sd->Element);
  879.             c = PopDirs(1);
  880.             if (ListOnly)
  881.             break;
  882.             if (GetTail(&DList) == NULL)    /*  may not be a parent */
  883.             break;
  884.             lock = ParentDir(lock);
  885.             if (lock == NULL) {
  886.             puts("Unable to ParentDir!");
  887.             notdone = 0;
  888.             } else {
  889.             if (c == 0)
  890.                 DeleteFile(Scr);
  891.             UnLock(CurrentDir(lock));
  892.             }
  893.         }
  894.         break;
  895.         case XDAT:
  896.         if (l != sizeof(DATESTAMP)) {
  897.             puts("expected sizeof datestamp");
  898.             notdone = 0;
  899.             break;
  900.         }
  901.         oread(&Date, l);
  902.         havedate = 1;
  903.         break;
  904.         case XPRO:
  905.         if (l != 4) {
  906.             puts("Expected 4 bytes for protection");
  907.             notdone = 0;
  908.             break;
  909.         }
  910.         oread(&Protection, l);
  911.         havepro = 1;
  912.         break;
  913.         case XCOM:
  914.         oread(Comment, l);
  915.         Comment[l] = 0;
  916.         havecom = 1;
  917.         break;
  918.         case XFIL0:
  919.         case XFIL1:
  920.         if (!havepro)
  921.             Protection = 0;
  922.         if (!havecom)
  923.             Comment[0] = 0;
  924.         if (!havedate)
  925.             DateStamp(&Date);
  926.         if (!haveinc)
  927.             IncSize = 0;
  928.  
  929.         oread(Scr, l);
  930.         Scr[l] = 0;
  931.         oread(&bytes, 4);       /*  length of file  */
  932.         actual = bytes;
  933.         if (c == XFIL1) {
  934.             oread(&actual, 4);
  935.             bytes -= 4;
  936.         }
  937.         setinputbound(bytes);
  938.         {
  939.             short res = read_file(c, Scr, bytes, actual);
  940.             seekinputend();
  941.             if (res < 0)
  942.             goto bend;
  943.         }
  944.         if (ListOnly)
  945.             goto bend;
  946.         if (Archive)
  947.             SetProtection(Scr, Protection|FIBF_ARCHIVE);
  948.         else
  949.             SetProtection(Scr, Protection&~FIBF_ARCHIVE);
  950.         if (havedate)
  951.             setfiledate(Scr, &Date);
  952.         if (havecom && Comment[0])
  953.             SetComment(Scr, Comment);
  954. bend:
  955.         havecom = havedate = havepro = haveinc = 0;
  956.         break;
  957.         case XHDR:
  958.         if (l != sizeof(DATESTAMP)) {
  959.             puts("expected sizeof datestamp");
  960.             notdone = 0;
  961.             break;
  962.         }
  963.         oread(&Date, l);
  964.         printf(" ----- BACKUP ----- BACKUP DATE: %s\n", datetos(&Date, Scr, NULL));
  965.         break;
  966.         case XINC:
  967.         if (l != 12) {
  968.             puts("expected 12 bytes for XINC");
  969.             notdone = 0;
  970.             break;
  971.         }
  972.         oread(&IncSize, 4);
  973.         oread(&IncSeek, 4);
  974.         oread(&IncLen,  4);
  975.         haveinc = 1;
  976.         break;
  977.         default:
  978.         printf("Unknown Record Type: %02x\n", c);
  979.         notdone = 0;
  980.         break;
  981.         }
  982.         setinputbound(-1);
  983.         if (mycheckbreak()) {
  984.         Break = 1;
  985.         notdone = 0;
  986.         break;
  987.         }
  988.     }
  989.     if (Break)
  990.         break;
  991.     }
  992.     UnLock(CurrentDir(SaveLock));
  993. }
  994.  
  995. FIB *
  996. GetFileInfo(path, plock)
  997. char *path;
  998. long *plock;
  999. {
  1000.     register long lock;
  1001.     register FIB *fib;
  1002.  
  1003.     *plock = NULL;
  1004.     if (lock = Lock(path, SHARED_LOCK)) {
  1005.     if (fib = malloc(sizeof(FIB))) {
  1006.         if (Examine(lock, fib)) {
  1007.         *plock = lock;
  1008.         return(fib);
  1009.         }
  1010.         free(fib);
  1011.     }
  1012.     UnLock(lock);
  1013.     }
  1014.     return(NULL);
  1015. }
  1016.  
  1017. FreeFileInfo(fib, lock)
  1018. FIB *fib;
  1019. long lock;
  1020. {
  1021.     if (fib)
  1022.     free(fib);
  1023.     if (lock)
  1024.     UnLock(lock);
  1025. }
  1026.  
  1027.  
  1028. PushDir(element, type)
  1029. char *element;
  1030. {
  1031.     register SDIR *sd = malloc(sizeof(SDIR));
  1032.     register char *str = malloc(strlen(element)+1);
  1033.  
  1034.     strcpy(str, element);
  1035.     sd->Type = type;
  1036.     sd->HaveFile = 0;
  1037.     sd->Element = str;
  1038.     AddTail(&DList, sd);
  1039.     strcat(DirPath+DPLen, str);
  1040.     if (type == XVOL)
  1041.     strcat(DirPath+DPLen, ":");
  1042.     else
  1043.     strcat(DirPath+DPLen, "/");
  1044.     DPLen += strlen(DirPath+DPLen);
  1045. }
  1046.  
  1047. PopDirs(num)
  1048. uword num;
  1049. {
  1050.     register SDIR *sd, *sp;
  1051.     char lasthave = 0;
  1052.  
  1053.     while (num && (sd = GetTail(&DList))) {
  1054.     lasthave |= sd->HaveFile;
  1055.     if (sd->HaveFile)       /*  MUST write end-block    */
  1056.         outentry(XEND, 0, NULL);
  1057.     if (sp = GetPred(sd))
  1058.         sp->HaveFile |= sd->HaveFile;
  1059.     Remove(sd);
  1060.     DPLen -= strlen(sd->Element) + 1;
  1061.     if (DPLen < 0) {
  1062.         puts("DPLEN ERROR");
  1063.         DPLen = 0;
  1064.     }
  1065.     DirPath[DPLen] = 0;
  1066.     free(sd->Element);
  1067.     free(sd);
  1068.     --num;
  1069.     }
  1070.     return(lasthave);
  1071. }
  1072.  
  1073. /*
  1074.  *  SCAN_DIRECTORY()        (CORE OF BACKUP)
  1075.  */
  1076.  
  1077. scan_directory(dirfib, dirlock)
  1078. FIB *dirfib;
  1079. long dirlock;
  1080. {
  1081.     register FIB *fib;
  1082.     long lock;
  1083.     long save = CurrentDir(dirlock);
  1084.  
  1085.     while (ExNext(dirlock, dirfib) && (fib = GetFileInfo(dirfib->fib_FileName, &lock))) {
  1086.     if (fib->fib_DirEntryType > 0) {
  1087.         PushDir(fib->fib_FileName, XDDS);
  1088.         if (ShowDirs)
  1089.         printf("%-40s (DIR)\n", DirPath);
  1090.         lock = scan_directory(fib, lock);
  1091.         PopDirs(1);
  1092.     } else {
  1093.         lock = scan_file(fib, lock);
  1094.     }
  1095.     FreeFileInfo(fib, lock);
  1096.     if (Break || mycheckbreak()) {
  1097.         Break = 1;
  1098.         break;
  1099.     }
  1100.     }
  1101.     CurrentDir(save);
  1102.     return(dirlock);
  1103. }
  1104.  
  1105. mycheckbreak()
  1106. {
  1107.     if (SetSignal(0, (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) & (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) {
  1108.     puts(" ***** BREAK *****");
  1109.     return(1);
  1110.     }
  1111.     return(0);
  1112. }
  1113.  
  1114. /*
  1115.  *  SCAN_FILE()
  1116.  *
  1117.  *  If the file is accepted, write out pending directory entries, do
  1118.  *  compression if any, and write out the file.
  1119.  */
  1120.  
  1121. scan_file(fib, lock)
  1122. FIB *fib;
  1123. long lock;
  1124. {
  1125.     long save;
  1126.     long n;
  1127.     char dbuf[32];
  1128.  
  1129.     strcat(DirPath, fib->fib_FileName);
  1130.  
  1131.     if (Update && (fib->fib_Protection & FIBF_ARCHIVE))
  1132.     goto nomatch;
  1133.     {
  1134.     register short i;
  1135.  
  1136.     for (i = 0; i < NumPicks; ++i) {
  1137.         if (wildcmp(Picks[i], DirPath))
  1138.         break;
  1139.     }
  1140.     if (i && i == NumPicks)
  1141.         goto nomatch;
  1142.  
  1143.     for (i = 0; i < NumDels; ++i) {
  1144.         if (wildcmp(Dels[i], DirPath))
  1145.         goto nomatch;
  1146.     }
  1147.     }
  1148.  
  1149.     if (ShowFiles)
  1150.     printf("%-40s %6ld %s\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
  1151.  
  1152.     {
  1153.     register SDIR *sd;
  1154.     SDIR *sdb = NULL;
  1155.  
  1156.     for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
  1157.         if (sd->HaveFile == 0)
  1158.         sdb = sd;
  1159.     }
  1160.     for (sd = sdb; sd; sd = GetSucc(sd)) {
  1161.         sd->HaveFile = 1;
  1162.         outentry(sd->Type, strlen(sd->Element), sd->Element);
  1163.     }
  1164.     }
  1165.     if (OutFile) {
  1166.     save = CurrentDir(lock);
  1167.     if (openinput("") == 0) {
  1168.         CurrentDir(save);
  1169.         printf("Unable to open %s\n", fib->fib_FileName);
  1170.         goto nomatch;
  1171.     }
  1172.     if (Compress && CompressFile(fib->fib_FileName, fib->fib_Size)) {
  1173.         if (OutFile && BacBytes && outbytes() + CLen > BacBytes) {
  1174.         if (newfile() == 0)
  1175.             goto skip1;
  1176.         }
  1177.         writeheaders(fib);
  1178.         outentry(XFIL1, strlen(fib->fib_FileName), fib->fib_FileName);
  1179.         CLen += 4;
  1180.         owrite(&CLen, 4);
  1181.         CLen -= 4;
  1182.         owrite(&fib->fib_Size, 4);
  1183.         transfer1(fib->fib_Size);
  1184.     } else {
  1185.         if (OutFile && BacBytes && outbytes() + fib->fib_Size > BacBytes) {
  1186.         if (newfile() == 0)
  1187.             goto skip1;
  1188.         }
  1189.         if (Compress)
  1190.         rollbackinput();
  1191.         writeheaders(fib);
  1192.         outentry(XFIL0, strlen(fib->fib_FileName), fib->fib_FileName);
  1193.         owrite(&fib->fib_Size, 4);
  1194.         transfer0(fib->fib_Size);
  1195.     }
  1196. skip1:
  1197.     closeinput();
  1198.     CurrentDir(save);
  1199.     }
  1200.     if (Break)
  1201.     goto nomatch;
  1202.     if (Archive && !(fib->fib_Protection & FIBF_ARCHIVE)) {
  1203.     if (save = ParentDir(lock)) {
  1204.         UnLock(lock);
  1205.         save = CurrentDir(save);
  1206.         SetProtection(fib->fib_FileName, fib->fib_Protection | FIBF_ARCHIVE);
  1207.         lock = CurrentDir(save);
  1208.     }
  1209.     }
  1210.     DirPath[DPLen] = 0;
  1211.     return(lock);
  1212. nomatch:
  1213.     if (Verbose)
  1214.     printf("%-40s (NOT ACCEPTED)\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
  1215.  
  1216.     DirPath[DPLen] = 0;
  1217.     return(lock);
  1218. }
  1219.  
  1220. writeheaders(fib)
  1221. register FIB *fib;
  1222. {
  1223.     outentry(XDAT, sizeof(DATESTAMP), &fib->fib_Date);
  1224.     outentry(XPRO, 4, &fib->fib_Protection);
  1225.     if (fib->fib_Comment[0])
  1226.     outentry(XCOM, strlen(fib->fib_Comment), fib->fib_Comment);
  1227. }
  1228.  
  1229. /*
  1230.  *  (1) Write out XEND's to finish this archive,
  1231.  *  (2) Open a new output file
  1232.  *  (3) Write out XDDS's to build back to the current position
  1233.  */
  1234.  
  1235. newfile()
  1236. {
  1237.     {
  1238.     register SDIR *sd;
  1239.  
  1240.     for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
  1241.         if (sd->HaveFile)
  1242.         outentry(XEND, 0, NULL);
  1243.     }
  1244.     }
  1245.     ++BacCnt;
  1246.     if (OutFile && openoutput(OutFile, Append, 1) == 0) {
  1247.     Break = 1;
  1248.     return(0);
  1249.     }
  1250.     {
  1251.     register SDIR *sd;
  1252.     DATESTAMP Date;
  1253.     DateStamp(&Date);
  1254.     outentry(XHDR, sizeof(DATESTAMP), &Date);
  1255.     for (sd = GetHead(&DList); sd; sd = GetSucc(sd)) {
  1256.         if (sd->HaveFile)
  1257.         outentry(sd->Type, strlen(sd->Element), sd->Element);
  1258.     }
  1259.     }
  1260.     return(1);
  1261. }
  1262.  
  1263. read_file(type, fname, inbytes, outbytes)
  1264. short type;
  1265. char *fname;
  1266. {
  1267.     char dbuf[32];
  1268.  
  1269.     strcat(DirPath, fname);
  1270.     {
  1271.     register short i;
  1272.  
  1273.     for (i = 0; i < NumPicks; ++i) {
  1274.         if (wildcmp(Picks[i], DirPath))
  1275.         break;
  1276.     }
  1277.     if (i && i == NumPicks) {
  1278.         if (Verbose)
  1279.         printf("%-40s (NOT ACCEPTED)\n", DirPath);
  1280.         goto nomatch;
  1281.     }
  1282.  
  1283.     for (i = 0; i < NumDels; ++i) {
  1284.         if (wildcmp(Dels[i], DirPath)) {
  1285.         if (Verbose)
  1286.             printf("%-40s (NOT ACCEPTED)\n", DirPath);
  1287.         goto nomatch;
  1288.         }
  1289.     }
  1290.     }
  1291.  
  1292.     printf("%-40s %6ld %6ld %s %s\n", DirPath, inbytes, outbytes, datetos(&Date, dbuf, NULL), Comment);
  1293.  
  1294.     if (ListOnly)
  1295.     goto nomatch;
  1296.     if (TimeStampOnly)
  1297.     goto matchskip;
  1298.  
  1299.     openoutput(fname, 0, 0);
  1300.     switch(type) {
  1301.     case XFIL0:
  1302.     transfer0(inbytes);
  1303.     break;
  1304.     case XFIL1:
  1305.     UnCompressFile(inbytes);
  1306.     transfer1(outbytes);
  1307.     break;
  1308.     }
  1309.     closeoutput();
  1310. matchskip:
  1311.     DirPath[DPLen] = 0;
  1312.     return(1);
  1313. nomatch:
  1314.     DirPath[DPLen] = 0;
  1315.     return(-1);
  1316. }
  1317.  
  1318. /*
  1319.  *  FILE SUPPORT
  1320.  */
  1321.  
  1322. static int Infd = -1;
  1323. static int Outfd = -1;
  1324. static long OutBytes;
  1325.  
  1326. openoutput(name, append, enabtail)
  1327. char *name;
  1328. {
  1329.     char *ptr = name;
  1330.     static NODE *VNode;     /*    Volume node */
  1331.     long lock;
  1332.     extern int errno;
  1333.  
  1334.     if (Outfd >= 0) {
  1335.     dumpoutput();
  1336.     close(Outfd);
  1337.     Outfd = -1;
  1338.     }
  1339.     if (enabtail) {
  1340.     if (VNode)
  1341.         VNode = GetSucc(VNode);
  1342.     if (!VNode)
  1343.         VNode = GetHead(&VList);
  1344.     if (VNode) {
  1345.         ptr = malloc(strlen(VNode->ln_Name)+strlen(name)+8);
  1346.         sprintf(ptr, "%s%s.%02ld", VNode->ln_Name, name, BacCnt);
  1347.     } else {
  1348.         ptr = malloc(strlen(name)+8);
  1349.         sprintf(ptr, "%s.%02ld", name, BacCnt);
  1350.     }
  1351.     }
  1352.     OutBytes = 0;
  1353.     while (GetHead(&VList)) {
  1354.     short c;
  1355.     short d;
  1356.  
  1357.     fprintf(stderr, "Ready for %s (y=go,n=abort) -", ptr);
  1358.     fflush(stderr);
  1359.     if ((c = getc(stdin)) == EOF) {
  1360.         fprintf(stderr, "EOF, aborted\n");
  1361.         c = 'n';
  1362.     }
  1363.     while ((d = getc(stdin)) != EOF && d != '\n');
  1364.     if ((c|0x20) == 'y')
  1365.         break;
  1366.     if ((c|0x20) == 'n')
  1367.         goto skip;
  1368.     }
  1369.     if (SaveLock)                       /*  original directory  */
  1370.     lock = CurrentDir(SaveLock);
  1371.     if (append) {
  1372.     Outfd = open(ptr, O_WRONLY|O_CREAT|O_APPEND);
  1373.     if (Outfd >= 0) {
  1374.         OutBytes = lseek(Outfd, 0L, 2);
  1375.         lseek(Outfd, 0L, 0);
  1376.     }
  1377.     } else {
  1378.     Outfd = open(ptr, O_WRONLY|O_CREAT|O_TRUNC);
  1379.     }
  1380.     if (SaveLock)                       /*  back to before      */
  1381.     CurrentDir(lock);
  1382.     if (Outfd < 0)
  1383.     printf("Unable to open output file %s (%ld)\n", ptr, errno);
  1384. skip:
  1385.     BufI = 0;
  1386.     if (enabtail)
  1387.     free(ptr);
  1388.     return(Outfd >= 0);
  1389. }
  1390.  
  1391. oputc(v)
  1392. char v;
  1393. {
  1394.     ++OutBytes;
  1395.     if (Outfd >= 0) {
  1396.     if (BufI == BufSize)
  1397.         dumpoutput();
  1398.     Buf[BufI++] = v;
  1399.     }
  1400. }
  1401.  
  1402. owrite(buf, n)
  1403. register char *buf;
  1404. register long n;
  1405. {
  1406.     register long avail;
  1407.  
  1408.     OutBytes += n;
  1409.     if (Outfd >= 0) {
  1410.     while (BufI + n > BufSize) {
  1411.         avail = BufSize - BufI;
  1412.         bmov(buf, Buf + BufI, avail);
  1413.         n  -= avail;
  1414.         buf+= avail;
  1415.         BufI = BufSize;
  1416.         dumpoutput();
  1417.     }
  1418.     bmov(buf, Buf + BufI, n);
  1419.     BufI += n;
  1420.     }
  1421. }
  1422.  
  1423. dumpoutput()
  1424. {
  1425.     if (Outfd >= 0 && BufI) {
  1426.     write(Outfd, Buf, BufI);
  1427.     BufI = 0;
  1428.     }
  1429. }
  1430.  
  1431. closeoutput()
  1432. {
  1433.     if (Outfd >= 0) {
  1434.     dumpoutput();
  1435.     close(Outfd);
  1436.     Outfd = -1;
  1437.     }
  1438. }
  1439.  
  1440. outbytes()
  1441. {
  1442.     return(OutBytes);
  1443. }
  1444.  
  1445. /*
  1446.  *  <type><len><buf>
  1447.  */
  1448.  
  1449. outentry(type, len, buf)
  1450. ubyte type;
  1451. ubyte len;
  1452. ubyte *buf;
  1453. {
  1454.     OutBytes += len + 2;
  1455.     if (Outfd >= 0) {
  1456.     if (BufI + len + 2 >= BufSize)
  1457.         dumpoutput();
  1458.     Buf[BufI+0] = type;
  1459.     Buf[BufI+1] = len;
  1460.     bmov(buf, Buf+BufI+2, len);
  1461.     BufI += len + 2;
  1462.     }
  1463. }
  1464.  
  1465. ulong OMax;
  1466.  
  1467. openinput(name)
  1468. char *name;
  1469. {
  1470.     if (Infd >= 0)
  1471.     close(Infd);
  1472.     Infd = open(name, O_RDONLY);
  1473.     InBufI = InBufN = 0;
  1474.     OMax = -1;
  1475.     return(Infd >= 0);
  1476. }
  1477.  
  1478. closeinput()
  1479. {
  1480.     if (Infd >= 0)
  1481.     close(Infd);
  1482.     Infd = -1;
  1483. }
  1484.  
  1485. void
  1486. seekinputend()
  1487. {
  1488.     register long inbuf   = InBufI - InBufN;
  1489.     register long forward = OMax;
  1490.  
  1491.     if (forward > inbuf) {
  1492.     lseek(Infd, forward - inbuf, 1);
  1493.     OMax = InBufI = InBufN = 0;
  1494.     return;
  1495.     }
  1496.     InBufN += forward;
  1497. }
  1498.  
  1499. setinputbound(max)
  1500. {
  1501.     OMax = max;
  1502. }
  1503.  
  1504. oread(buf, n)
  1505. char *buf;
  1506. long n;
  1507. {
  1508.     long x = 0;
  1509.     long avail;
  1510.  
  1511.     if (Infd < 0)
  1512.     return(0);
  1513.     if (n > OMax)
  1514.     n = OMax;
  1515.  
  1516.     while (n > (avail = InBufI - InBufN)) {
  1517.     if (InBufN == -1)
  1518.         return(0);
  1519.     bmov(InBuf + InBufN, buf, avail);
  1520.     OMax-= avail;
  1521.     n   -= avail;
  1522.     buf += avail;
  1523.     x   += avail;
  1524.     InBufI = read(Infd, InBuf, InBufSize);
  1525.     InBufN = 0;
  1526.     if (InBufI <= 0) {
  1527.         InBufI = 0;
  1528.         return(x);
  1529.     }
  1530.     }
  1531.     bmov(InBuf + InBufN, buf, n);
  1532.     InBufN += n;
  1533.     x += n;
  1534.     OMax -= n;
  1535.     return(x);
  1536. }
  1537.  
  1538. oreadchar()
  1539. {
  1540.     if (!OMax || Infd < 0)
  1541.     return(-1);
  1542.     if (InBufN == InBufI) {
  1543.     if (InBufN < 0)
  1544.         return(EOF);
  1545.     InBufI = read(Infd, InBuf, InBufSize);
  1546.     InBufN = 0;
  1547.     if (InBufI == 0) {
  1548.         InBufN = InBufI = -1;
  1549.         return(-1);
  1550.     }
  1551.     }
  1552.     return(InBuf[InBufN++]);
  1553. }
  1554.  
  1555. rollbackinput()
  1556. {
  1557.     if (Infd >= 0)
  1558.     lseek(Infd, 0L, 0);
  1559.     InBufI = InBufN = 0;
  1560. }
  1561.  
  1562. mputc(v)
  1563. char v;
  1564. {
  1565.     register SCOMP *sc = CWrite;
  1566.  
  1567.     ++CLen;
  1568.     if (sc->N == sc->Bytes) {
  1569.     sc = GetSucc(sc);
  1570.     if (sc == NULL);
  1571.         sc = NewSComp();
  1572.     if (sc == NULL) {
  1573.         puts("SCOMP FAILED");
  1574.         return(0);
  1575.     }
  1576.     sc->N = 0;
  1577.     CWrite = sc;
  1578.     }
  1579.     ((char *)(sc + 1))[sc->N++] = v;
  1580. }
  1581.  
  1582. mwrite(buf, n)
  1583. char *buf;
  1584. long n;
  1585. {
  1586.     register SCOMP *sc = CWrite;
  1587.     register long avail;
  1588.  
  1589.     CLen += n;
  1590.     while ((avail = sc->Bytes - sc->N) < n) {
  1591.     bmov(buf, (char *)(sc + 1) + sc->N, avail);
  1592.     buf += avail;
  1593.     n -= avail;
  1594.     sc->N = sc->Bytes;
  1595.     sc = GetSucc(sc);
  1596.     if (sc == NULL)
  1597.         sc = NewSComp();
  1598.     if (sc == NULL) {
  1599.         puts("SCOMP FAILED");
  1600.         return(0);
  1601.     }
  1602.     sc->N = 0;
  1603.     }
  1604.     bmov(buf, (char *)(sc + 1) + sc->N, n);
  1605.     sc->N += n;
  1606.     CWrite = sc;
  1607. }
  1608.  
  1609. SCOMP *
  1610. NewSComp()
  1611. {
  1612.     register SCOMP *sc = malloc(sizeof(SCOMP) + 8192);
  1613.  
  1614.     if (sc) {
  1615.     sc->Bytes = 8192;
  1616.     sc->N = 0;
  1617.     AddTail(&CList, sc);
  1618.     }
  1619.     return(sc);
  1620. }
  1621.  
  1622. transfer0(n)
  1623. long n;
  1624. {
  1625.     register long len;
  1626.  
  1627.     if (Outfd < 0)
  1628.     return(n);
  1629.     for (len = BufSize - BufI; n; len = BufSize - BufI) {
  1630.     if (len == 0) {
  1631.         dumpoutput();
  1632.         len = BufSize;
  1633.     }
  1634.     if (n < len)
  1635.         len = n;
  1636.     oread(Buf + BufI, len);
  1637.     BufI += len;
  1638.     n -= len;
  1639.     OutBytes += len;
  1640.     }
  1641. }
  1642.  
  1643. /*
  1644.  *  Compression Routines
  1645.  *
  1646.  *  transfer1(n)    : Backup:   copy compression buffer to output file
  1647.  */
  1648.  
  1649. transfer1(a)
  1650. {
  1651.     register long len;
  1652.     register SCOMP *sc = GetHead(&CList);
  1653.     register ubyte *ptr;
  1654.     long n = CLen;
  1655.  
  1656.     if (Outfd < 0)
  1657.     return(n);
  1658.     for (sc = GetHead(&CList); sc && n; sc = GetSucc(sc)) {
  1659.     len = sc->Bytes;
  1660.     ptr = (ubyte *)(sc + 1);
  1661.     if (n < len)
  1662.         len = n;
  1663.     n -= len;
  1664.     while (len > BufSize - BufI) {
  1665.         bmov(ptr, Buf + BufI, BufSize - BufI);
  1666.         ptr += BufSize - BufI;
  1667.         len -= BufSize - BufI;
  1668.         OutBytes += BufSize - BufI;
  1669.         BufI = BufSize;
  1670.         dumpoutput();
  1671.     }
  1672.     bmov(ptr, Buf + BufI, len);
  1673.     BufI += len;
  1674.     OutBytes += len;
  1675.     }
  1676.     if (n)
  1677.     puts("Unexpected EOF in compression file");
  1678. }
  1679.  
  1680. #asm
  1681.  
  1682.         ;    Taken from my DRES.LIBRARY so we don't have to open the
  1683.         ;    library.
  1684.  
  1685.         public  _GetHead
  1686.         public  _GetTail
  1687.         public  _GetSucc
  1688.         public  _GetPred
  1689.  
  1690. _GetSucc:
  1691. _GetHead:   move.l  4(sp),A0
  1692.         move.l  (A0),A0
  1693.         tst.l   (A0)
  1694.         bne     .gh1
  1695. .ghz        sub.l   A0,A0
  1696. .gh1        move.l  A0,D0
  1697.         rts
  1698.  
  1699. _GetTail:   move.l  4(sp),A0
  1700.         move.l  8(A0),A0
  1701.         tst.l   4(A0)
  1702.         beq     .ghz
  1703.         move.l  A0,D0
  1704.         rts
  1705.  
  1706. _GetPred:   move.l  4(sp),A0
  1707.         move.l  4(A0),A0
  1708.         tst.l   4(A0)
  1709.         beq     .ghz
  1710.         move.l  A0,D0
  1711.         rts
  1712.  
  1713. #endasm
  1714.  
  1715. #define ngetchar()  oreadchar()
  1716. #define nputchar(n) mputc(n)
  1717.  
  1718. #ifndef min
  1719. #define min(a,b)        ((a>b) ? b : a)
  1720. #endif
  1721.  
  1722. #define BITS        13
  1723.  
  1724. #if BITS == 16
  1725. #define HSIZE  69001           /* 95% occupancy */
  1726. #endif
  1727. #if BITS == 15
  1728. #define HSIZE  35023           /* 94% occupancy */
  1729. #endif
  1730. #if BITS == 14
  1731. #define HSIZE  18013           /* 91% occupancy */
  1732. #endif
  1733. #if BITS == 13
  1734. #define HSIZE  9001           /* 91% occupancy */
  1735. #endif
  1736. #if BITS <= 12
  1737. #define HSIZE  5003           /* 80% occupancy */
  1738. #endif
  1739.  
  1740. typedef long        code_int;
  1741. typedef long        count_int;
  1742. typedef unsigned char    char_type;
  1743.  
  1744. #define MAXCODE(n_bits)  ((1 << (n_bits)) - 1)
  1745. #define INIT_BITS 9            /* initial number of bits/code */
  1746.  
  1747. int n_bits;                /* number of bits/code            */
  1748. int maxbits;                /* user settable max # bits/code    */
  1749. code_int maxcode;            /* maximum code, given n_bits        */
  1750. code_int maxmaxcode;            /* should NEVER generate this code  */
  1751.  
  1752. count_int   htab[HSIZE];
  1753. uword        codetab[HSIZE];
  1754.  
  1755. #define htabof(i)       htab[i]
  1756. #define codetabof(i)    codetab[i]
  1757.  
  1758. code_int hsize = HSIZE;         /* for dynamic table sizing */
  1759.  
  1760. #define tab_prefixof(i)     codetabof(i)
  1761. #define tab_suffixof(i)     ((char_type *)(htab))[i]
  1762. #define de_stack        ((char_type *)&tab_suffixof(1<<BITS))
  1763.  
  1764. code_int free_ent;            /* first unused entry */
  1765.  
  1766. code_int getcode();
  1767.  
  1768. #define CHECK_GAP 10000 /* ratio check interval */
  1769.  
  1770. int    block_compress = 1;
  1771. int    clear_flg;
  1772. long    ratio;
  1773. count_int checkpoint;
  1774.  
  1775. /*
  1776.  * the next two codes should not be changed lightly, as they must not
  1777.  * lie within the contiguous general code space.
  1778.  */
  1779.  
  1780. #define FIRST    257    /* first free entry */
  1781. #define CLEAR    256    /* table clear output code */
  1782.  
  1783. static int offset;
  1784. long int in_count = 1;            /* length of input */
  1785.  
  1786. /*
  1787.  *  Compress a file to memory-buffers and return TRUE if the compressed
  1788.  *  size is smaller than the actual size.
  1789.  */
  1790.  
  1791. CompressFile(name, fsize)
  1792. {
  1793.     long fcode;
  1794.     code_int i = 0;
  1795.     int c;
  1796.     code_int ent;
  1797.     int disp;
  1798.     code_int hsize_reg;
  1799.     int hshift;
  1800.  
  1801.     if (wildcmp("*.Z", name) || wildcmp("*.ARC", name) || wildcmp("*.ZOO", name)) {
  1802.     printf("  Will not compress %s\n", name);
  1803.     return(0);
  1804.     }
  1805.  
  1806.     CLen = 0;
  1807.     CWrite = GetHead(&CList);
  1808.     if (CWrite == NULL)
  1809.     CWrite = NewSComp();
  1810.     CWrite->N = 0;
  1811.  
  1812.     bzero(htab, sizeof(htab));
  1813.     bzero(codetab, sizeof(codetab));
  1814.  
  1815.     hsize = HSIZE;
  1816.     if ( fsize < (1 << 12) )
  1817.     hsize = min ( 5003, HSIZE );
  1818.     else if ( fsize < (1 << 13) )
  1819.     hsize = min ( 9001, HSIZE );
  1820.     else if ( fsize < (1 << 14) )
  1821.     hsize = min ( 18013, HSIZE );
  1822.     else if ( fsize < (1 << 15) )
  1823.     hsize = min ( 35023, HSIZE );
  1824.     else if ( fsize < 47000 )
  1825.     hsize = min ( 50021, HSIZE );
  1826.  
  1827.     offset = clear_flg = ratio = 0;
  1828.     in_count = 1;
  1829.     checkpoint = CHECK_GAP;
  1830.     n_bits  = INIT_BITS;        /* number of bits/code            */
  1831.     maxbits = BITS;            /* user settable max # bits/code    */
  1832.     maxcode = MAXCODE(INIT_BITS);       /* maximum code, given n_bits       */
  1833.     maxmaxcode = 1 << BITS;        /* should NEVER generate this code  */
  1834.     free_ent = ((block_compress) ? FIRST : 256 );
  1835.  
  1836.     ent = ngetchar();
  1837.  
  1838.     hshift = 0;
  1839.     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
  1840.     hshift++;
  1841.     hshift = 8 - hshift;        /* set hash code range bound */
  1842.  
  1843.     hsize_reg = hsize;
  1844.     cl_hash((count_int)hsize_reg);      /* clear hash table */
  1845.  
  1846.     while ((c = ngetchar()) != EOF) {
  1847.     in_count++;
  1848.     fcode = (long) (((long) c << maxbits) + ent);
  1849.     i = ((c << hshift) ^ ent);      /* xor hashing */
  1850.  
  1851.     if (htabof (i) == fcode) {
  1852.         ent = codetabof(i);
  1853.         continue;
  1854.     } else if ((long)htabof (i) < 0)    /* empty slot */
  1855.         goto nomatch;
  1856.     disp = hsize_reg - i;        /* secondary hash (after G. Knott) */
  1857.     if (i == 0)
  1858.         disp = 1;
  1859. probe:
  1860.     if ((i -= disp) < 0)
  1861.         i += hsize_reg;
  1862.  
  1863.     if (htabof (i) == fcode) {
  1864.         ent = codetabof(i);
  1865.         continue;
  1866.     }
  1867.     if ((long)htabof (i) > 0)
  1868.         goto probe;
  1869. nomatch:
  1870.     output ((code_int) ent);
  1871.     ent = c;
  1872.     if (free_ent < maxmaxcode) {
  1873.         codetabof(i) = free_ent++; /* code -> hashtable */
  1874.         htabof(i) = fcode;
  1875.     }
  1876.     else if ((count_int)in_count >= checkpoint && block_compress)
  1877.         cl_block ();
  1878.     }
  1879.  
  1880.     /*
  1881.      * Put out the final code.
  1882.      */
  1883.  
  1884.     output((code_int)ent);
  1885.     output((code_int)-1);
  1886.  
  1887.     return(CLen < fsize);
  1888. }
  1889.  
  1890. static char buf[BITS];
  1891.  
  1892. char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
  1893. char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
  1894.  
  1895. output( code )
  1896. code_int  code;
  1897. {
  1898.     register int r_off = offset, bits= n_bits;
  1899.     register char * bp = buf;
  1900.  
  1901.     if ( code >= 0 ) {
  1902.     /*
  1903.      * Get to the first byte.
  1904.      */
  1905.     bp += (r_off >> 3);
  1906.     r_off &= 7;
  1907.     /*
  1908.      * Since code is always >= 8 bits, only need to mask the first
  1909.      * hunk on the left.
  1910.      */
  1911.     *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
  1912.     bp++;
  1913.     bits -= (8 - r_off);
  1914.     code >>= 8 - r_off;
  1915.     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  1916.     if ( bits >= 8 ) {
  1917.         *bp++ = code;
  1918.         code >>= 8;
  1919.         bits -= 8;
  1920.     }
  1921.     /* Last bits. */
  1922.     if(bits)
  1923.         *bp = code;
  1924.  
  1925.     offset += n_bits;
  1926.     if (offset == (n_bits << 3)) {
  1927.         bp = buf;
  1928.         bits = n_bits;
  1929.         mwrite(bp, bits);
  1930.         bp += bits;
  1931.         bits = 0;
  1932.         offset = 0;
  1933.     }
  1934.  
  1935.     /*
  1936.      * If the next entry is going to be too big for the code size,
  1937.      * then increase it, if possible.
  1938.      */
  1939.  
  1940.     if (free_ent > maxcode || (clear_flg > 0)) {
  1941.         /*
  1942.          * Write the whole buffer, because the input side won't
  1943.          * discover the size increase until after it has read it.
  1944.          */
  1945.         if (offset > 0)
  1946.         mwrite(buf, n_bits);
  1947.         offset = 0;
  1948.  
  1949.         if (clear_flg) {
  1950.         n_bits = INIT_BITS;
  1951.         maxcode = MAXCODE(INIT_BITS);
  1952.         clear_flg = 0;
  1953.         } else {
  1954.         n_bits++;
  1955.         if (n_bits == maxbits)
  1956.             maxcode = maxmaxcode;
  1957.         else
  1958.             maxcode = MAXCODE(n_bits);
  1959.         }
  1960.     }
  1961.     } else {
  1962.     /*
  1963.      * At EOF, write the rest of the buffer.
  1964.      */
  1965.     if (offset > 0)
  1966.         mwrite(buf, (offset + 7) / 8);
  1967.     offset = 0;
  1968.     }
  1969. }
  1970.  
  1971.  
  1972. char *
  1973. xrindex(s, c)            /* For those who don't have it in libc.a */
  1974. register char *s, c;
  1975. {
  1976.     char *p;
  1977.     for (p = NULL; *s; s++) {
  1978.     if (*s == c)
  1979.         p = s;
  1980.     }
  1981.     return(p);
  1982. }
  1983.  
  1984.  
  1985. cl_block()             /* table clear for block compress */
  1986. {
  1987.     register long int rat;
  1988.  
  1989.     checkpoint = in_count + CHECK_GAP;
  1990.  
  1991.     if (in_count > 0x007fffff) { /* shift will overflow */
  1992.     rat = CLen >> 8;
  1993.     if (rat == 0) {          /* Don't divide by zero */
  1994.         rat = 0x7fffffff;
  1995.     } else {
  1996.         rat = in_count / rat;
  1997.     }
  1998.     } else {
  1999.     rat = (in_count << 8) / CLen;      /* 8 fractional bits */
  2000.     }
  2001.     if (rat > ratio) {
  2002.     ratio = rat;
  2003.     } else {
  2004.     ratio = 0;
  2005.     cl_hash ( (count_int) hsize );
  2006.     free_ent = FIRST;
  2007.     clear_flg = 1;
  2008.     output ( (code_int) CLEAR );
  2009.     }
  2010. }
  2011.  
  2012. cl_hash(hsize)          /* reset code table */
  2013.     register count_int hsize;
  2014. {
  2015.     register count_int *htab_p = htab+hsize;
  2016.     register long i;
  2017.     register long m1 = -1;
  2018.  
  2019.     i = hsize - 16;
  2020.     do {                /* might use Sys V memset(3) here */
  2021.         *(htab_p-16) = m1;
  2022.         *(htab_p-15) = m1;
  2023.         *(htab_p-14) = m1;
  2024.         *(htab_p-13) = m1;
  2025.         *(htab_p-12) = m1;
  2026.         *(htab_p-11) = m1;
  2027.         *(htab_p-10) = m1;
  2028.         *(htab_p-9) = m1;
  2029.         *(htab_p-8) = m1;
  2030.         *(htab_p-7) = m1;
  2031.         *(htab_p-6) = m1;
  2032.         *(htab_p-5) = m1;
  2033.         *(htab_p-4) = m1;
  2034.         *(htab_p-3) = m1;
  2035.         *(htab_p-2) = m1;
  2036.         *(htab_p-1) = m1;
  2037.         htab_p -= 16;
  2038.     } while ((i -= 16) >= 0);
  2039.     for ( i += 16; i > 0; i-- )
  2040.         *--htab_p = m1;
  2041. }
  2042.  
  2043. UnCompressFile(insize)
  2044. {
  2045.     register char_type *stackp;
  2046.     register int finchar;
  2047.     register code_int code, oldcode, incode;
  2048.  
  2049.     /*
  2050.      * As above, initialize the first 256 entries in the table.
  2051.      */
  2052.  
  2053.     bzero(htab, sizeof(htab));
  2054.     bzero(codetab, sizeof(codetab));
  2055.  
  2056.     offset = clear_flg = ratio = 0;
  2057.     in_count = 1;
  2058.     checkpoint = CHECK_GAP;
  2059.     n_bits  = INIT_BITS;        /* number of bits/code            */
  2060.     maxbits = BITS;            /* user settable max # bits/code    */
  2061.     maxcode = MAXCODE(INIT_BITS);       /* maximum code, given n_bits       */
  2062.     maxmaxcode = 1 << BITS;        /* should NEVER generate this code  */
  2063.  
  2064.     for ( code = 255; code >= 0; code-- ) {
  2065.     tab_prefixof(code) = 0;
  2066.     tab_suffixof(code) = (char_type)code;
  2067.     }
  2068.     free_ent = ((block_compress) ? FIRST : 256 );
  2069.  
  2070.     finchar = oldcode = getcode();
  2071.     if (oldcode == -1)          /* EOF already? */
  2072.     return;         /* Get out of here */
  2073.     oputc((char)finchar);       /* first code must be 8 bits = char */
  2074.     stackp = de_stack;
  2075.  
  2076.     while ((code = getcode()) > -1) {
  2077.     if ((code == CLEAR) && block_compress) {
  2078.         for (code = 255; code >= 0; code--)
  2079.         tab_prefixof(code) = 0;
  2080.         clear_flg = 1;
  2081.         free_ent = FIRST - 1;
  2082.         if ((code = getcode()) == -1)   /* O, untimely death! */
  2083.         break;
  2084.     }
  2085.     incode = code;
  2086.     /*
  2087.      * Special case for KwKwK string.
  2088.      */
  2089.     if (code >= free_ent) {
  2090.         *stackp++ = finchar;
  2091.         code = oldcode;
  2092.     }
  2093.  
  2094.     /*
  2095.      * Generate output characters in reverse order
  2096.      */
  2097.     while ( code >= 256 ) {
  2098.         *stackp++ = tab_suffixof(code);
  2099.         code = tab_prefixof(code);
  2100.     }
  2101.     *stackp++ = finchar = tab_suffixof(code);
  2102.  
  2103.     /*
  2104.      * And put them out in forward order
  2105.      */
  2106.     do
  2107.         oputc (*--stackp);
  2108.     while (stackp > de_stack);
  2109.  
  2110.     /*
  2111.      * Generate the new entry.
  2112.      */
  2113.     if ((code=free_ent) < maxmaxcode) {
  2114.         tab_prefixof(code) = (unsigned short)oldcode;
  2115.         tab_suffixof(code) = finchar;
  2116.         free_ent = code+1;
  2117.     }
  2118.     /*
  2119.      * Remember previous code.
  2120.      */
  2121.     oldcode = incode;
  2122.     }
  2123. }
  2124.  
  2125. code_int
  2126. getcode()
  2127. {
  2128.     /*
  2129.      * On the VAX, it is important to have the register declarations
  2130.      * in exactly the order given, or the asm will break.
  2131.      */
  2132.  
  2133.     register code_int code;
  2134.     static int offset = 0, size = 0;
  2135.     static char_type buf[BITS];
  2136.     register int r_off, bits;
  2137.     register char_type *bp = buf;
  2138.  
  2139.     if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
  2140.     /*
  2141.      * If the next entry will be too big for the current code
  2142.      * size, then we must increase the size.  This implies reading
  2143.      * a new buffer full, too.
  2144.      */
  2145.     if ( free_ent > maxcode ) {
  2146.         n_bits++;
  2147.         if ( n_bits == maxbits )
  2148.         maxcode = maxmaxcode;    /* won't get any bigger now */
  2149.         else
  2150.         maxcode = MAXCODE(n_bits);
  2151.     }
  2152.     if ( clear_flg > 0) {
  2153.         maxcode = MAXCODE (n_bits = INIT_BITS);
  2154.         clear_flg = 0;
  2155.     }
  2156.     size = oread(buf, n_bits);
  2157.     if (size <= 0)
  2158.         return -1;            /* end of file */
  2159.     offset = 0;
  2160.     size = (size << 3) - (n_bits - 1);
  2161.     }
  2162.     r_off = offset;
  2163.     bits = n_bits;
  2164.  
  2165.     /*
  2166.      * Get to the first byte.
  2167.      */
  2168.     bp += (r_off >> 3);
  2169.     r_off &= 7;
  2170.     /* Get first part (low order bits) */
  2171.  
  2172.     code = (*bp++ >> r_off);
  2173.  
  2174.     bits -= (8 - r_off);
  2175.     r_off = 8 - r_off;        /* now, offset into code word */
  2176.     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  2177.     if ( bits >= 8 ) {
  2178.         code |= *bp++ << r_off;
  2179.         r_off += 8;
  2180.         bits -= 8;
  2181.     }
  2182.     /* high order bits. */
  2183.     code |= (*bp & rmask[bits]) << r_off;
  2184.  
  2185.     offset += n_bits;
  2186.  
  2187.     return code;
  2188. }
  2189.  
  2190. \Rogue\Monster\
  2191. else
  2192.   echo "will not over write backup.c"
  2193. fi
  2194. if [ `wc -c backup.c | awk '{printf $1}'` -ne 37210 ]
  2195. then
  2196. echo `wc -c backup.c | awk '{print "Got " $1 ", Expected " 37210}'`
  2197. fi
  2198. echo "Finished archive 1 of 1"
  2199. # if you want to concatenate archives, remove anything after this line
  2200. exit
  2201. -- 
  2202. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  2203. Have five nice days.
  2204.